﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Microsoft.SharePoint;
using CMISForSharePoint.cmisHelpers;
using CMISForSharePoint.cmisEnums;
using CMISForSharePoint.cmisTypes;
using System.Reflection;
using System.Diagnostics;
using System.Security.Principal;
using System.Runtime.InteropServices;


namespace CMISForSharePoint.cmisHelpers
{
    public class SPHelper : IDisposable
    {

        #region Members of SPHelper
        /// <summary>
        /// A string that will store the name of the SharePoint farm, by default it's localhost because we assume 
        /// CMIS4SharePoint is installed in the sharepoint server
        /// </summary>
        private static string _SPHost = "http://localhost";
       
        /// <summary>
        /// An instance of SPSite, this instance is like the singleton design pattern it simulate a "Session" because
        /// SharePoint works with session and Web-services(WS-I) do not have such thing
        /// </summary>
        private static SPSite localSiteCollection;


        /// <summary>
        /// an attribute to access _SPHost
        /// </summary>
        public string SPHost
        {
            get { return _SPHost; }
            set {

                if (Uri.IsWellFormedUriString(value, UriKind.RelativeOrAbsolute))
                {
                    _SPHost = value;
                }
                else
                {
                    throw new InvalidOperationException("Invalid URL for the SPHost");
                }


            }
        }

        #endregion

        #region Methods for SPhelper

        #region Static Methods for init the SPsite
        /// <summary>
        /// Releases the SPSite ressources
        /// </summary>
        #region IDisposable Membres

        void IDisposable.Dispose()
        {
            if (localSiteCollection != null)
            {
                localSiteCollection.Dispose();
                localSiteCollection.Close();
                localSiteCollection = null;

            }
        }



        #endregion
        /// <summary>
        /// Initiate the SPSite as a static member using the provided URL in SPHost
        /// </summary>
        public static void InitSite()
        {

            if (localSiteCollection == null)
            {
                localSiteCollection = new SPSite(SPHelper._SPHost);
             
            }
        }


        public SPHelper()
        {
            InitSite();
        }

        public SPHelper(string siteUrl)
        {
            if (!String.IsNullOrEmpty(siteUrl))
            {
                _SPHost = siteUrl;
                InitSite();
            }
            else
            {
                throw new InvalidOperationException();
            }
        }
        #endregion

        #region Content Type Mapping Methods
        /// <summary>
        /// Converts the SharePoint Objects SPContentType to enumObjectType
        /// <remarks>
        /// the mapping is done according to this document http://msdn.microsoft.com/en-us/library/ms452896.aspx
        /// and http://msdn.microsoft.com/en-us/library/ms549876.aspx
        /// </remarks>
        /// </summary>
        /// <param name="contentType"> A sharePoint Content type</param>
        /// <returns> A value of enumObjectType</returns>
        public enumObjectType SPContentTypeToEnumCmisType(SPContentType contentType)
        {
            string contentId = contentType.Id.ToString();
            if (contentId.StartsWith("0x0101"))
            {
                if (contentId.StartsWith("0x010101"))
                {
                    return enumObjectType.policy;
                }
                else
                {
                    return enumObjectType.document;
                }
            }
            else if (contentId.StartsWith("0x0120"))
            {
                return enumObjectType.folder;

            }
            else if (contentId.StartsWith("0x0105"))
            {
                return enumObjectType.relationship;
            }
            else
            {
                return enumObjectType.policy;
            }

        }

        /// <summary>
        /// Makes the mapping between the object SPContent Type and the cmisTypeDefinitionType
        /// </summary>
        /// <param name="myContentType">an object SPContentType</param>
        /// <returns>a cmisTypeDefinitionType </returns>
        public cmisTypeDefinitionType SPContentTypeToCmisDefinitionType(SPContentType myContentType)
        {
            cmisTypeDefinitionType myType = null;
            //depending on the CMIS type in the Enum we create an adequate object
            switch (SPContentTypeToEnumCmisType(myContentType))
            {
                case enumObjectType.document:
                    cmisTypeDocumentDefinitionType myDocType = new cmisTypeDocumentDefinitionType();
                    myDocType.contentStreamAllowed = enumContentStreamAllowed.allowed;
                    myDocType.versionable = true;
                    myType = myDocType;
                    break;
                case enumObjectType.folder:
                    cmisTypeFolderDefinitionType myFolType = new cmisTypeFolderDefinitionType();
                    myType = myFolType;
                    break;
                case enumObjectType.relationship:
                    cmisTypeRelationshipDefinitionType myRelType = new cmisTypeRelationshipDefinitionType();
                    myRelType.allowedSourceTypes = null;
                    myRelType.allowedTargetTypes = null;
                    myType = myRelType;
                    break;
                case enumObjectType.policy:
                    cmisTypePolicyDefinitionType myPolType = new cmisTypePolicyDefinitionType();
                    myType = myPolType;
                    break;

            } //using polymorphism we cast previous type to the parent type "cmisTypeDefinitionType "

           
            //we complete the filling of the type
            myType.typeId = myContentType.Id.ToString();
            myType.queryName = myContentType.Name;
            myType.displayName = myContentType.Name;
            myType.baseType = SPContentTypeToEnumCmisType(myContentType);
            myType.baseTypeQueryName = myType.baseType.ToString();
            myType.parentId = myContentType.Parent.Id.ToString();
            myType.description = myContentType.Description;
            myType.creatable = IsCreatable(myType.baseType);
            myType.controllable=IsControllable(myType.baseType);
            myType.fileable = IsFileable(myType.baseType);
            myType.queryable = IsQueryable(myType.baseType);
            myType.includedInSupertypeQuery = IsIncludeInSuperTypeQuery(myType.baseType);
            


            return myType;

        }


        /// <summary>
        /// Makes the mapping between the object SPField and the cmisPropertyDefinitionType, it'actually a restricted mapping for CMIS 
        /// we only map the: SPFieldType.Boolean, SPFieldType.File, SPFieldType.DateTime, SPFieldType.Guid, SPFieldType.Integer, SPFieldType.Number,
        /// SPFieldType.Text, SPFieldType.URL
        /// </summary>
        /// <param name="field"> an SP field object</param>
        /// <returns>a cmisPropertyDefinitionType </returns>
        public cmisPropertyDefinitionType SPFieldToCmisPropertyDefinitionType(SPField field)
        {
            cmisPropertyDefinitionType myProperty = new cmisPropertyDefinitionType();
            switch (field.Type)
            {


                case SPFieldType.Boolean:
                    {
                        cmisPropertyBooleanDefinitionType myBoolProp = new cmisPropertyBooleanDefinitionType();
                        myBoolProp.propertyType = enumPropertyType.boolean;
                        myProperty = myBoolProp;
                        break;
                    }

                case SPFieldType.File:
                    {
                        cmisPropertyXmlDefinitionType myXmlProp = new cmisPropertyXmlDefinitionType();
                        myXmlProp.propertyType = enumPropertyType.xml;
                        myXmlProp.schemaURI = field.SchemaXml;
                        myXmlProp.encoding = "UTF-8";
                        myProperty = myXmlProp;
                        break;
                    }

                case SPFieldType.DateTime:
                    {
                        cmisPropertyDateTimeDefinitionType myDateProp = new cmisPropertyDateTimeDefinitionType();
                        myDateProp.propertyType = enumPropertyType.datetime;
                        myProperty = myDateProp;
                        break;
                    }

                case SPFieldType.Guid:
                    {
                        cmisPropertyIdDefinitionType myIdProp = new cmisPropertyIdDefinitionType();
                        myIdProp.propertyType = enumPropertyType.id;
                        myProperty = myIdProp;
                        break;
                    }
                case SPFieldType.Integer:
                    {
                        cmisPropertyIntegerDefinitionType myIntProp = new cmisPropertyIntegerDefinitionType();
                        myIntProp.propertyType = enumPropertyType.integer;
                        myIntProp.minValue = int.MinValue.ToString();
                        myIntProp.maxValue = int.MaxValue.ToString();

                        myProperty = myIntProp;
                        break;
                    }

                case SPFieldType.Number:
                    {
                        cmisPropertyDecimalDefinitionType myDecProp = new cmisPropertyDecimalDefinitionType();
                        myDecProp.propertyType = enumPropertyType.@decimal;
                        myDecProp.precision = enumDecimalPrecision.Item64;
                        myDecProp.precisionSpecified = true;//for xmlSerializer
                        myProperty = myDecProp;
                        break;
                    }

                case SPFieldType.Text:
                    {
                        cmisPropertyStringDefinitionType myStrProp = new cmisPropertyStringDefinitionType();
                        myStrProp.propertyType = enumPropertyType.@string;
                        myStrProp.maxLength = "256";
                        myProperty = myStrProp;
                        break;
                    }

                case SPFieldType.URL:
                    {
                        cmisPropertyUriDefinitionType myUriProp = new cmisPropertyUriDefinitionType();
                        myUriProp.propertyType = enumPropertyType.uri;
                        myProperty = myUriProp;
                        break;
                    }

                default:
                    {
                        //here we return a null value because there are some calculate field in SharePoint and we don't need to map them
                        return null;


                    }


            }

            myProperty.name = field.InternalName;
            myProperty.id = field.Id.ToString();
            myProperty.displayName = field.Title;
            myProperty.description = field.Description;
            myProperty.inherited = field.FromBaseType;
            myProperty.cardinality = field.Sortable ? enumCardinality.single : enumCardinality.multi;
            myProperty.openChoice = false;
            myProperty.openChoiceSpecified = false;//this value is for the xml serializer
            myProperty.Items = null;
            myProperty.required = field.Required;
            myProperty.updateability = field.ReadOnlyField ? enumUpdateability.@readonly : enumUpdateability.whencheckedout;
            myProperty.queryable = !field.NoCrawl;
            myProperty.orderable = field.Sortable;
            
           

            return myProperty;
        }

        #region Test for Content Type Mapping
        /// <summary>
        /// Indicates if the value of type is creatable according to the mapping from SharePoint to CMIS
        /// </summary>
        /// <param name="type">A CmisEnum Object containing CMIS types</param>
        /// <returns>true if creatable false otherways</returns>
        public bool IsCreatable(enumObjectType type)
        {
            switch (type)
            {
                case enumObjectType.document:
                    return true;

                case enumObjectType.folder:
                    return true;

                case enumObjectType.relationship:
                    return false;

                case enumObjectType.policy:
                    return false;

                default:
                    return false;

            }
        }

        /// <summary>
        /// Indicates if the value of type is fileable according to the mapping from SharePoint to CMIS
        /// </summary>
        /// <param name="type">A CmisEnum Object containing CMIS types</param>
        /// <returns>true if fileable false otherways</returns>
        public bool IsFileable(enumObjectType type)
        {
            switch (type)
            {
                case enumObjectType.document:
                    return true;

                case enumObjectType.folder:
                    return true;

                case enumObjectType.relationship:
                    return false;

                case enumObjectType.policy:
                    return false;

                default:
                    return false;

            }
        }

        /// <summary>
        /// Indicates if the value of type is queryable according to the mapping from SharePoint to CMIS
        /// </summary>
        /// <param name="type">A CmisEnum Object containing CMIS types</param>
        /// <returns>true if queryable false otherways</returns>
        public bool IsQueryable(enumObjectType type)
        {
            switch (type)
            {
                case enumObjectType.document:
                    return true;

                case enumObjectType.folder:
                    return true;

                case enumObjectType.relationship:
                    return false;

                case enumObjectType.policy:
                    return false;

                default:
                    return false;

            }
        }

        /// <summary>
        /// Indicates if the value of type is controllable according to the mapping from SharePoint to CMIS
        /// </summary>
        /// <param name="type">A CmisEnum Object containing CMIS types</param>
        /// <returns>true if controllable false otherways</returns>
        public bool IsControllable(enumObjectType type)
        {
            switch (type)
            {
                case enumObjectType.document:
                    return true;

                case enumObjectType.folder:
                    return true;

                case enumObjectType.relationship:
                    return false;

                case enumObjectType.policy:
                    return false;

                default:
                    return false;

            }
        }

        /// <summary>
        /// Indicates if the value of type is included in SuperTypeQuery according to the mapping from SharePoint to CMIS
        /// </summary>
        /// <param name="type">A CmisEnum Object containing CMIS types</param>
        /// <returns>true if included in SuperTypeQuery false otherways</returns>
        public bool IsIncludeInSuperTypeQuery(enumObjectType type)
        {
            switch (type)
            {
                case enumObjectType.document:
                    return true;

                case enumObjectType.folder:
                    return true;

                case enumObjectType.relationship:
                    return false;

                case enumObjectType.policy:
                    return false;

                default:
                    return false;

            }
        }
        #endregion
        #endregion


        /// <summary>
        /// Gets all the Documents libraries available within the specified SPSite in the SPHost parametere
        /// </summary>
        /// <returns>A List of Douments library</returns>
        public List<SPDocumentLibrary> GetDocumentLibraries()
        {
            List<SPDocumentLibrary> responseList = new List<SPDocumentLibrary>();

            //initiating the SPsite and ensuring the dispose
            SPHelper spHelper = new SPHelper();
          
            SPWebCollection localWebCollection = localSiteCollection.AllWebs;
           
                
                foreach (SPWeb myWeb in localWebCollection)
                {              
                    SPListCollection localListCollection = myWeb.Lists;
                    foreach (SPList myList in localListCollection)
                    {
                      
                        if (myList.BaseType == SPBaseType.DocumentLibrary)
                        {
                            SPDocumentLibrary myDocLib = myList as SPDocumentLibrary;
                            if (myDocLib.BaseTemplate == SPListTemplateType.DocumentLibrary)
                            {

                                if (!myDocLib.Hidden)
                                {
                                    string fold = myDocLib.RootFolder.Url;
                                    responseList.Add(myDocLib);

                                }
                            }
                        }
                    }
                }


            return responseList;

        }

        /// <summary>
        /// Gets an unique Document Library, using the GUID
        /// </summary>
        /// <param name="id">the GUID of the Document Library</param>
        /// <returns> A Document Library</returns>
        public SPDocumentLibrary GetDocumentLibrary(Guid id)
        {
            List<SPDocumentLibrary> librariesList = GetDocumentLibraries();
            foreach (SPDocumentLibrary myDocLib in librariesList)
            {
                if (myDocLib.ID.Equals(id))
                {
                    return myDocLib;

                }

            }

            return null;
        }

        /// <summary>
        /// gets a cmisObject the represents a Tree containing all the files and folders starting from the specified SPFolder
        /// and going as deep as the depth parameter
        /// </summary>
        /// <param name="obj">A cmisObjectType wich will hold all the tree</param>
        /// <param name="folder">An SPFolder which is the root of the tree in SharePoint</param>
        /// <param name="depth">The level where the tree crossing must stop </param>
        /// <returns></returns>
        public cmisObjectType SPfolderTreeToCmisObjectType(cmisObjectType obj, SPFolder folder, int depth, string[] filter, enumTypesOfFileableObjects types, bool includeAllowableActions, enumRelationshipDirection relationDirection, string orderByClause)
        {




            if (depth >= 0)
            {
                depth--;

                //we set the cmis properties for our folder
                obj = cmisFolderFactory(folder);

                //here we choose our properties specified in the filter
                obj.properties.Items = CmisHelper.CmisPropertyFilter(obj.properties.Items, filter);

                //settings the nb of items to deal with
                int nbOfItems;
                switch (types)
                {
                    case enumTypesOfFileableObjects.documents:
                        nbOfItems = folder.Files.Count;
                        break;
                    case enumTypesOfFileableObjects.folders:
                        nbOfItems = folder.SubFolders.Count;
                        break;
                    case enumTypesOfFileableObjects.policies:
                        //each folder item can provide only one content type from which we could take the policy
                        nbOfItems = 1;
                        break;
                    case enumTypesOfFileableObjects.any:
                        nbOfItems = folder.SubFolders.Count + folder.Files.Count + 1;
                        break;
                    default:
                        nbOfItems = 0;
                        break;
                }

                //allocating the child array & the relationships array
                if (nbOfItems > 0)
                {
                    obj.child = new cmisObjectType[nbOfItems];
                    obj.relationship = new cmisObjectType[nbOfItems];

                }

                #region Dealing with folders
                //filling the child array with folders first
                if (types == enumTypesOfFileableObjects.folders || types == enumTypesOfFileableObjects.any)
                {

                    if (folder.SubFolders.Count > 0)
                    {
                        SPFolder child;
                        SPFolderCollection subFolders = folder.SubFolders;
                        for (int i = 0; i < folder.SubFolders.Count; i++)
                        {
                            //the folder Forms is a system folder so we avoid to expose it
                            if (subFolders[i].Name != "Forms")
                            {
                                child = subFolders[i];
                            }
                            else
                            {
                                continue;
                            }
                            //recursive call of the function to get all the sub folders until the reach of the depth
                            obj.child[i] = SPfolderTreeToCmisObjectType(obj.child[i], child, depth, filter, types, includeAllowableActions, relationDirection, orderByClause);

                            #region not suported :Relationship
                            ///the relationship paradigm is'not available within sharePoint
                            //obj.relationship[i] = cmisRelationshipFactory(child.Item, relationDirection);
                            #endregion
                        }
                    }
                }
                #endregion
                #region Dealing with files
                //filling the child array with files
                if (types == enumTypesOfFileableObjects.documents || types == enumTypesOfFileableObjects.any)
                {

                    if (folder.Files.Count > 0)
                    {
                        int j = 0;
                        int start;
                        int end;
                        SPFileCollection fileCollection = folder.Files;
                        //managing the array index
                        if (types != enumTypesOfFileableObjects.any)
                        {
                            start = 0;
                            end = nbOfItems;
                        }
                        else
                        {
                            start = folder.SubFolders.Count;
                            end = nbOfItems - 1;
                        }
                        for (int i = start; i < end; i++)
                        {
                            //this condition is to deal with the forms in the root folder (they don't have item)
                            if (fileCollection[j].Item != null)
                            {


                                obj.child[i] = cmisDocumentFactory(fileCollection[j]);
                                //here we choose our properties specified in the filter
                                obj.child[i].properties.Items = CmisHelper.CmisPropertyFilter(obj.child[i].properties.Items, filter);
                                #region not suported :Relationship
                                ///the relationship paradigm is'not available within sharePoint
                                //obj.relationship[i] = cmisRelationshipFactory(folder.Files[j].Item, relationDirection);
                                #endregion
                            } j++;


                        }
                    }
                }
                #endregion
                #region Dealing with policies
                //filling the child array with policies
                if (types == enumTypesOfFileableObjects.policies || types == enumTypesOfFileableObjects.any)
                {
                    //the condition deals with the case of Root-folder wich always contain a null item property
                    if (folder.Item != null)
                    {
                        if (obj.child.Count() > 0)
                        {

                            obj.child[nbOfItems - 1] = cmisPolicyFactory(folder.Item);
                            //here we choose our properties specified in the filter
                            obj.child[nbOfItems - 1].properties.Items = CmisHelper.CmisPropertyFilter(obj.child[nbOfItems - 1].properties.Items, filter);

                            if (obj.child[nbOfItems - 1].properties.Items.Count() == 0)
                            {
                                obj.child[nbOfItems - 1] = null;
                                nbOfItems--;
                            }


                        }



                    }
                }
                #endregion

                //including AllowableActions
                if (includeAllowableActions == true && folder.Item != null)
                {
                    obj.allowableActions = cmisAllowableActionsFactory(folder.Item);
                }

                //sorting
                if (!String.IsNullOrEmpty(orderByClause) && obj.child != null)
                {
                    string[] orderingParam = CmisHelper.OrderByClauseParser(orderByClause);
                    if (orderingParam.Count() > 0)
                    {
                        CmisObjectSorter.PropertyName = orderingParam[0];
                        Func<cmisObjectType, string> objKeyGetter = new Func<cmisObjectType, string>(CmisObjectSorter.GetKey);
                        if (string.Compare(orderingParam[1], "ASC", StringComparison.OrdinalIgnoreCase) == 0)
                        {


                            obj.child = obj.child.OrderBy(objKeyGetter, new CmisObjectSorter()).ToArray();

                        }
                        else
                        {

                            obj.child = obj.child.OrderByDescending(objKeyGetter, new CmisObjectSorter()).ToArray();

                        }
                    }


                }
                return obj;

            }



            return null;



        }


        /// <summary>
        /// Gets a cmisAllowableActionsType wich maps all the allowable actions for the User in the SPListItem and it uses
        /// the SPBasePermissions Mask to choose the value of the permission
        /// </summary>
        /// <param name="item">An SPListItem</param>
        /// <returns>cmisAllowableActionsType or null if no available item (ex:ROOT-FOLDER doesn't have an SPListItem)</returns>
        public cmisAllowableActionsType cmisAllowableActionsFactory(SPListItem item)
        {

            if (item != null)
            {
                cmisAllowableActionsType allowableActions = new cmisAllowableActionsType();

                allowableActions.canAddPolicy = item.DoesUserHavePermissions(SPBasePermissions.ManagePermissions);
                allowableActions.canAddPolicySpecified = true;

                allowableActions.canAddToFolder = item.DoesUserHavePermissions(SPBasePermissions.BrowseDirectories | SPBasePermissions.AddListItems);
                allowableActions.canAddToFolderSpecified = true;

                allowableActions.canCancelCheckout = item.DoesUserHavePermissions(SPBasePermissions.CancelCheckout);
                allowableActions.canCancelCheckoutSpecified = true;

                allowableActions.canCheckin = item.DoesUserHavePermissions(SPBasePermissions.ApproveItems);
                allowableActions.canCheckinSpecified = true;

                allowableActions.canCheckout = item.DoesUserHavePermissions(SPBasePermissions.EditListItems);
                allowableActions.canCheckoutSpecified = true;

                allowableActions.canCreateDocument = item.DoesUserHavePermissions(SPBasePermissions.BrowseDirectories | SPBasePermissions.AddListItems);
                allowableActions.canCreateDocumentSpecified = true;

                allowableActions.canCreateFolder = item.DoesUserHavePermissions(SPBasePermissions.AddListItems);
                allowableActions.canCreateFolderSpecified = true;

                allowableActions.canCreatePolicy = item.DoesUserHavePermissions(SPBasePermissions.ManagePermissions);
                allowableActions.canCreatePolicySpecified = true;

                allowableActions.canCreateRelationship = item.DoesUserHavePermissions(SPBasePermissions.AddListItems);
                allowableActions.canCreateRelationshipSpecified = true;

                allowableActions.canDelete = item.DoesUserHavePermissions(SPBasePermissions.DeleteListItems);
                allowableActions.canDeleteSpecified = true;

                allowableActions.canDeleteContent = item.DoesUserHavePermissions(SPBasePermissions.DeleteListItems);
                allowableActions.canDeleteContentSpecified = true;

                allowableActions.canDeleteTree = item.DoesUserHavePermissions(SPBasePermissions.DeleteListItems);
                allowableActions.canDeleteTreeSpecified = true;

                allowableActions.canDeleteVersion = item.DoesUserHavePermissions(SPBasePermissions.DeleteVersions);
                allowableActions.canDeleteVersionSpecified = true;

                allowableActions.canGetAllVersions = item.DoesUserHavePermissions(SPBasePermissions.ViewVersions);
                allowableActions.canGetAllVersionsSpecified = true;

                allowableActions.canGetAppliedPolicies = item.DoesUserHavePermissions(SPBasePermissions.ManagePermissions);
                allowableActions.canGetAppliedPoliciesSpecified = true;

                allowableActions.canGetChildren = item.DoesUserHavePermissions(SPBasePermissions.BrowseDirectories);
                allowableActions.canGetChildrenSpecified = true;

                allowableActions.canGetDescendants = item.DoesUserHavePermissions(SPBasePermissions.BrowseDirectories);
                allowableActions.canGetDescendantsSpecified = true;

                allowableActions.canGetFolderParent = item.DoesUserHavePermissions(SPBasePermissions.BrowseDirectories);
                allowableActions.canGetFolderParentSpecified = true;

                allowableActions.canGetParents = item.DoesUserHavePermissions(SPBasePermissions.BrowseDirectories);
                allowableActions.canGetParentsSpecified = true;

                allowableActions.canGetProperties = item.DoesUserHavePermissions(SPBasePermissions.ViewListItems);
                allowableActions.canGetPropertiesSpecified = true;

                allowableActions.canGetRelationships = item.DoesUserHavePermissions(SPBasePermissions.ViewListItems);
                allowableActions.canGetRelationshipsSpecified = true;

                allowableActions.canMove = item.DoesUserHavePermissions(SPBasePermissions.EditListItems);
                allowableActions.canMoveSpecified = true;

                allowableActions.canRemoveFromFolder = item.DoesUserHavePermissions(SPBasePermissions.EditListItems);
                allowableActions.canRemoveFromFolderSpecified = true;

                allowableActions.canRemovePolicy = item.DoesUserHavePermissions(SPBasePermissions.EditListItems);
                allowableActions.canRemovePolicySpecified = true;

                allowableActions.canSetContent = item.DoesUserHavePermissions(SPBasePermissions.EditListItems);
                allowableActions.canSetContentSpecified = true;

                allowableActions.canUpdateProperties = item.DoesUserHavePermissions(SPBasePermissions.EditListItems);
                allowableActions.canUpdatePropertiesSpecified = true;

                allowableActions.canViewContent = item.DoesUserHavePermissions(SPBasePermissions.Open);
                allowableActions.canViewContentSpecified = true;

                allowableActions.parentId = item.UniqueId.ToString();
                allowableActions.parentUrl = item.Url;





                return allowableActions;
            }
            return null;
        }

        #region TRASH

        public void GetFilesFromTree(SPFolder root, ref List<SPFile> fileCollection)
        {

            foreach (SPFile file in root.Files)
            {
                fileCollection.Add(file);
            }
            foreach (SPFolder folder in root.SubFolders)
            {
                GetFilesFromTree(folder, ref fileCollection);
            }


        }



        #endregion


        #region cmisObjectType Factories
        //could be useless
        /// <summary>
        /// Gets a cmisObjectType using the available informations in the SPListItem
        /// </summary>
        /// <remarks>could be useless</remarks>
        /// <param name="item">An SPListItem</param>
        /// <returns>A base cmisObjectType</returns>
        public cmisObjectType cmisObjectTypeFactory(SPListItem item)
        {
            cmisObjectType obj = new cmisObjectType();
            List<cmisProperty> objProperties = new List<cmisProperty>();

            objProperties.Add(cmisPropertyIdFactory("ObjectId", item.UniqueId.ToString(), "0", string.Empty));
            objProperties.Add(cmisPropertyUriFactory("URI", item.Url, "1"));
            objProperties.Add(cmisPropertyIdFactory("ObjectTypeId", item.ContentType.Id.ToString(), "2", string.Empty));
            objProperties.Add(cmisPropertyStringFactory("CreatedBy", item.File != null ? item.File.Author.Name : string.Empty, "3"));
            objProperties.Add(cmisPropertyDateTimeFactory("CreationDate", item.File != null ? item.File.TimeCreated : (DateTime)item.Folder.Properties["vti_timecreated"], "4"));
            objProperties.Add(cmisPropertyStringFactory("LastModifiedBy", item.File != null ? item.File.ModifiedBy.Name : string.Empty, "5"));
            objProperties.Add(cmisPropertyDateTimeFactory("LastModificationDate", item.File != null ? item.File.TimeLastModified : (DateTime)item.Folder.Properties["vti_timelastmodified"], "6"));

            //!!!!remark:not accurate, could be a wrong mapping
            objProperties.Add(cmisPropertyStringFactory("ChangeToken", item.Audit.AuditFlags.ToString(), "7"));

            obj.properties = new cmisPropertiesType();
            obj.properties.Items = new cmisProperty[0];
            obj.properties.Items = objProperties.ToArray();

            return obj;

        }

        //still need the allowable actions and relationships
        /// <summary>
        /// Gets a cmisObjectType from a SPFile
        /// </summary>
        /// <remarks>doesn't provide the allowable actions and relationships </remarks>
        /// <param name="file">An SPFile object</param>
        /// <returns>A file cmisObjectType</returns>
        public cmisObjectType cmisDocumentFactory(SPFile file)
        {
            cmisObjectType cmisDoc = new cmisObjectType();
            List<cmisProperty> objProperties = new List<cmisProperty>();

            //creating a base cmisObjectType
            cmisDoc = cmisObjectTypeFactory(file.Item);

            //filling properties
            objProperties.Add(cmisPropertyStringFactory("Name", file.Name, "8"));
            objProperties.Add(cmisPropertyBooleanFactory("IsImmutable", !file.Item.DoesUserHavePermissions(SPBasePermissions.OpenItems), "9"));
            objProperties.Add(cmisPropertyBooleanFactory("IsLatestVersion", file.Versions.File.Equals(file), "10"));
            objProperties.Add(cmisPropertyBooleanFactory("IsMajorVersion", file.MinorVersion == 0, "11"));
            objProperties.Add(cmisPropertyBooleanFactory("IsLatestMajorVersion", ((file.MinorVersion == 0) && (file.Versions.File.MajorVersion == file.MajorVersion)), "12"));
            objProperties.Add(cmisPropertyStringFactory("VersionLabel", file.UIVersionLabel, "13"));
            objProperties.Add(cmisPropertyIdFactory("VersionSeriesId", file.Versions.File.UniqueId.ToString(), "14", string.Empty));
            objProperties.Add(cmisPropertyBooleanFactory("IsVersionSeriesCheckedOut", file.Level == SPFileLevel.Checkout, "15"));
            objProperties.Add(cmisPropertyStringFactory("VersionSeriesCheckedOutBy", file.Level == SPFileLevel.Checkout ? file.CheckedOutBy.Name : string.Empty, "16"));
            objProperties.Add(cmisPropertyStringFactory("CheckinComment", file.CheckInComment, "17"));
            objProperties.Add(cmisPropertyStringFactory("ContentStreamAllowed", enumContentStreamAllowed.allowed.ToString(), "18"));
            objProperties.Add(cmisPropertyIntegerFactory("ContentStreamLength", file.Length.ToString(), "19"));
            objProperties.Add(cmisPropertyStringFactory("ContentStreamMimeType", MimeType(file.Name), "20"));
            objProperties.Add(cmisPropertyStringFactory("ContentStreamFilename", file.Name, "21"));
            objProperties.Add(cmisPropertyUriFactory("ContentStreamUri", file.Url, "22"));

            //converting from a List of properties to an array
            cmisDoc.properties.Items = cmisDoc.properties.Items.Concat(objProperties.ToArray()).ToArray();
            cmisAllowableActionsType type = new cmisAllowableActionsType();

            return cmisDoc;

        }


        //needs validation and if possible refactoring
        /// <summary>
        /// Gets a cmisObjectType from a SPFolder
        /// </summary>
        /// <remarks>needs validation and if possible refactoring</remarks>
        /// <param name="folder">An SPFolder object</param>
        /// <returns>A folder cmisObjectType</returns>
        public cmisObjectType cmisFolderFactory(SPFolder folder)
        {
            cmisObjectType cmisFold = new cmisObjectType();
            List<cmisProperty> objProperties = new List<cmisProperty>();

            objProperties.Add(cmisPropertyIdFactory("ObjectId", folder.UniqueId.ToString(), "0", string.Empty));
            objProperties.Add(cmisPropertyUriFactory("URI", folder.Url, "1"));
            objProperties.Add(cmisPropertyIdFactory("ObjectTypeId", folder.ContentTypeOrder[0].Id.ToString(), "2", string.Empty));
            objProperties.Add(cmisPropertyStringFactory("CreatedBy", string.Empty, "3"));
            objProperties.Add(cmisPropertyDateTimeFactory("CreationDate", DateTime.Now, "4"));
            objProperties.Add(cmisPropertyStringFactory("LastModifiedBy", string.Empty, "5"));
            objProperties.Add(cmisPropertyDateTimeFactory("LastModificationDate", DateTime.Now, "6"));
            objProperties.Add(cmisPropertyStringFactory("ChangeToken", folder.Audit.AuditFlags.ToString(), "7"));




            //Detecting root folder
            if (String.IsNullOrEmpty(folder.ParentFolder.Name))
            {

                objProperties.Add(cmisPropertyStringFactory("Name", "CMIS_Root_Folder", "8"));
                objProperties.Add(cmisPropertyIdFactory("ParentId", folder.UniqueId.ToString(), "9", string.Empty));
                objProperties.Add(cmisPropertyIdFactory("AllowedChildObjectTypeIds", string.Empty, "10", string.Empty));
            }
            else
            {

                objProperties.Add(cmisPropertyStringFactory("Name", folder.Name, "8"));
                objProperties.Add(cmisPropertyIdFactory("ParentId", folder.ParentFolder.UniqueId.ToString(), "9", string.Empty));
                objProperties.Add(cmisPropertyIdFactory("AllowedChildObjectTypeIds", string.Empty, "10", string.Empty));
            }

            cmisFold.properties = new cmisPropertiesType();
            cmisFold.properties.Items = new cmisProperty[0];
            cmisFold.properties.Items = objProperties.ToArray();

            return cmisFold;
        }

        //i'm not sure about the relationships in sharePoint because it's a little bit tricky and unclear
        /// <summary>
        /// Gets a cmisObjectType from a SPListItem and an enumRelationshipDirection objects
        /// </summary>
        /// <remarks>Not sure about the relationships in sharePoint because it's a little bit tricky and unclear</remarks>
        /// <param name="item">SPListItem</param>
        /// <param name="relationDirection">enumRelationshipDirection</param>
        /// <returns>A relationship cmisObjectType</returns>
        public cmisObjectType cmisRelationshipFactory(SPListItem item, enumRelationshipDirection relationDirection)
        {
            if (item != null)
            {
                cmisObjectType cmisRel = new cmisObjectType();
                List<cmisProperty> objProperties = new List<cmisProperty>();

                cmisRel = cmisObjectTypeFactory(item);
                if (relationDirection == enumRelationshipDirection.source || relationDirection == enumRelationshipDirection.both)
                {
                    try
                    {

                        objProperties.Add(cmisPropertyIdFactory("SourceId", item.BackwardLinks.Count > 0 ? item.BackwardLinks[0].Url : string.Empty, "8", string.Empty));

                    }
                    catch (Exception)
                    {

                        return null;
                    }
                }
                if (relationDirection == enumRelationshipDirection.target || relationDirection == enumRelationshipDirection.both)
                {
                    try
                    {

                        objProperties.Add(cmisPropertyIdFactory("TargetId", item.ForwardLinks.Count > 0 ? item.ForwardLinks[0].Url : string.Empty, "9", string.Empty));

                    }
                    catch (Exception)
                    {

                        return null;
                    }
                }

                cmisRel.properties.Items = cmisRel.properties.Items.Concat(objProperties.ToArray()).ToArray();

                return cmisRel;
            }

            return null;

        }
        //i'm not sure about the policy in sharePoint because it's a little bit tricky and unclear
        /// <summary>
        /// Gets a cmisObjectType from a SPListItem
        /// </summary>
        /// <remarks>needs validation and if possible refactoring</remarks>
        /// <param name="item">An SPFolder object</param>
        /// <returns>A policy cmisObjectType</returns>
        public cmisObjectType cmisPolicyFactory(SPListItem item)
        {
            if (item != null)
            {
                cmisObjectType cmisPol = new cmisObjectType();
                List<cmisProperty> objProperties = new List<cmisProperty>();

                cmisPol = cmisObjectTypeFactory(item);

                objProperties.Add(cmisPropertyStringFactory("PolicyName", item.ContentType.Name + "Policy", "8"));
                objProperties.Add(cmisPropertyStringFactory("PolicyText", item.ContentType.XmlDocuments.Count > 0 ? item.ContentType.XmlDocuments[0].ToString() : string.Empty, "9"));

                cmisPol.properties.Items = cmisPol.properties.Items.Concat(objProperties.ToArray()).ToArray();
                return cmisPol;
            }
            return null;

        }

        #endregion

       
        #region CmisProperties Factories
        /// <summary>
        /// A factory to create a cmisPropertyId object
        /// </summary>
        /// <param name="name">The name of the property</param>
        /// <param name="value">The value of the property</param>
        /// <param name="index">the index (could be empty)</param>
        /// <param name="href">the URI of the property (could be empty)</param>
        /// <returns>a cmisPropertyId object</returns>
        public cmisPropertyId cmisPropertyIdFactory(string name, string value, string index, string href)
        {
            cmisPropertyId response = new cmisPropertyId();

            response.name = name;
            response.value = value;
            response.index = index;
            response.href = href;

            response.propertyType = enumPropertyType.id;

            return response;
        }
        
        /// <summary>
        /// A factory to create a cmisPropertyInteger object
        /// </summary>
        /// <param name="name">The name of the property</param>
        /// <param name="value">The value of the property</param>
        /// <param name="index">the index (could be empty)</param>
        /// <returns>a cmisPropertyInteger object</returns>
        public cmisPropertyInteger cmisPropertyIntegerFactory(string name, string value, string index)
        {
            cmisPropertyInteger response = new cmisPropertyInteger();
            response.name = name;
            response.value = value;
            response.index = index;

            response.propertyType = enumPropertyType.integer;

            return response;
        }
       
        /// <summary>
        /// A factory to create a cmisPropertyBoolean object
        /// </summary>
        /// <param name="name">The name of the property</param>
        /// <param name="value">The value of the property</param>
        /// <param name="index">the index (could be empty)</param>
        /// <returns>a cmisPropertyBoolean object</returns>
        public cmisPropertyBoolean cmisPropertyBooleanFactory(string name, bool value, string index)
        {
            cmisPropertyBoolean response = new cmisPropertyBoolean();

            response.name = name;
            response.value = value;
            response.index = index;
            response.valueSpecified = true;

            response.propertyType = enumPropertyType.boolean;

            return response;
        }

        /// <summary>
        /// A factory to create a cmisPropertyDateTime object
        /// </summary>
        /// <param name="name">The name of the property</param>
        /// <param name="value">The value of the property</param>
        /// <param name="index">the index (could be empty)</param>
        /// <returns> a cmisPropertyDateTime object</returns>
        public cmisPropertyDateTime cmisPropertyDateTimeFactory(string name, DateTime value, string index)
        {
            cmisPropertyDateTime response = new cmisPropertyDateTime();

            response.name = name;
            response.value = value;
            response.index = index;
            response.valueSpecified = true;

            response.propertyType = enumPropertyType.datetime;

            return response;

        }
        
        /// <summary>
        /// A factory to create a cmisPropertyDecimal object
        /// </summary>
        /// <param name="name">The name of the property</param>
        /// <param name="value">The value of the property</param>
        /// <param name="index">the index (could be empty)</param>
        /// <returns> a cmisPropertyDecimal object</returns>
        public cmisPropertyDecimal cmisPropertyDecimalFactory(string name, decimal value, string index)
        {
            cmisPropertyDecimal response = new cmisPropertyDecimal();

            response.name = name;
            response.value = value;
            response.index = index;
            response.valueSpecified = true;

            response.propertyType = enumPropertyType.@decimal;

            return response;

        }

        /// <summary>
        /// A factory to create a cmisPropertyString object
        /// </summary>
        /// <param name="name">The name of the property</param>
        /// <param name="value">The value of the property</param>
        /// <param name="index">the index (could be empty)</param>
        /// <returns> a cmisPropertyString object</returns>
        public cmisPropertyString cmisPropertyStringFactory(string name, string value, string index)
        {
            cmisPropertyString response = new cmisPropertyString();

            response.name = name;
            response.value = value;
            response.index = index;

            response.propertyType = enumPropertyType.@string;

            return response;
        }

        /// <summary>
        /// A factory to create a cmisPropertyUri object
        /// </summary>
        /// <param name="name">The name of the property</param>
        /// <param name="value">The value of the property</param>
        /// <param name="index">the index (could be empty)</param>
        /// <returns> a cmisPropertyUri object</returns>
        public cmisPropertyUri cmisPropertyUriFactory(string name, string value, string index)
        {
            cmisPropertyUri response = new cmisPropertyUri();

            response.name = name;
            response.value = value;
            response.index = index;

            response.propertyType = enumPropertyType.uri;

            return response;
        }

        #endregion

        /// <summary>
        /// It fills the properties of an SPFile starting from an array of cmisProperty
        /// </summary>
        /// <remarks>Uses SetCmisPropertyToSPListItem</remarks>
        /// <param name="properties">the cmisProperties (all properties should have a compliant SharePoint name)</param>
        /// <param name="file">the file in which we apply the properties</param>
        /// <returns>the updated SPFile</returns>
        public SPFile SetCmisPropertyToSPfile(cmisProperty[] properties, SPFile file)
        {
            SPListItem item = file.Item;

            if (item != null)
            {

                item = SetCmisPropertyToSPListItem(properties, item);
                item.Update();
                return item.File;
            }
            else
            {
                return null;
            }
        }
       
        /// <summary>
        /// It fills the properties of an SPFolder starting from an array of cmisProperty
        /// </summary>
        /// <remarks>Uses SetCmisPropertyToSPListItem</remarks>
        /// <param name="properties">the cmisProperties (all properties should have a compliant SharePoint name)</param>
        /// <param name="folder">the folder in which we apply the properties</param>
        /// <returns>the updated SPFolder</returns>
        public SPFolder SetCmisPropertyToSPfolder(cmisProperty[] properties, SPFolder folder)
        {
            SPListItem item = folder.Item;

            if (item != null)
            {

                item = SetCmisPropertyToSPListItem(properties, item);
                item.Update();
                return item.Folder;
            }
            else
            {
                return null;
            }

        }

        /// <summary>
        /// It fills the properties of an SPItem starting from an array of cmisProperty
        /// </summary>
        /// <param name="properties">the cmisProperties (all properties should have a compliant SharePoint name)</param>
        /// <param name="item">the item in which we apply the properties</param>
        /// <returns>the updated SPListItem</returns>
        private SPListItem SetCmisPropertyToSPListItem(cmisProperty[] properties, SPListItem item)
        {
            Type t;

            if (item != null)
            {

                foreach (cmisProperty property in properties)
                {
                    if (property != null)
                    {
                        object rollBack = item[property.name];
                        t = property.GetType();
                        try
                        {

                            item[property.name] = t.InvokeMember("value",
                                                                 BindingFlags.Public | BindingFlags.NonPublic |
                                                                 BindingFlags.Instance | BindingFlags.GetProperty,
                                                                 null, property, null);

                            item.Update();

                        }
                        catch (Exception e)
                        {
                            Debug.WriteLine("SetCmisPropertyToSPListItem : " + e.Message);
                        }

                    }


                }
            }

            return item;

        }

     
        #region 3rd party code
        /// <summary>
        /// Gets the mime type from the server
        /// </summary>
        /// <remarks>it uses the registry of the server this function should be refactored</remarks>
        /// <param name="Filename">the file name with the extension</param>
        /// <returns>a string containing the mime type of the application</returns>
        public string MimeType(string Filename)
        {
            string mime = "application/octetstream";
            string ext = System.IO.Path.GetExtension(Filename).ToLower();
            Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
            if (rk != null && rk.GetValue("Content Type") != null)
                mime = rk.GetValue("Content Type").ToString();
            return mime;
        }


        //Add a reference to System.DirectoryServices and a reference to 'Active DS IIS Namespace Provider' under the COM tab. The extension needs to have the leading dot, i.e. '.flv'.
        //public static string GetMimeTypeFromExtension(string extension) 
        //{
        //    using (DirectoryEntry mimeMap = new DirectoryEntry("IIS://Localhost/MimeMap"))
        //    { 
        //        PropertyValueCollection propValues = mimeMap.Properties["MimeMap"];
        //        foreach (object value in propValues)
        //        { 
        //            IISOle.IISMimeType mimeType = (IISOle.IISMimeType)value;
        //            if (extension == mimeType.Extension)
        //            {
        //                return mimeType.MimeType;
        //            } 
        //        } return null;
        //    }
        //}

        #endregion
        #endregion





    }
}
